AWS Step Functionsでタスク毎に別アカウントのロールにAssumeRole(スイッチロール)出来るようになりました!
お疲れさまです。とーちです。
最近は AWS re:Invent 2022 の開催が近いせいかすごい数のアップデートが AWS から発表されてますね。
そんなアップデートの中でも個人的にオッと思ったアップデートである AWS Step Functions のクロスアカウントアクセスに関するアップデートをご紹介したいと思います。
かんたんまとめ
- ステートマシン内のタスク単位で別アカウントのロールに AssumeRole できるようになった
- リソースベースポリシーをサポートしていない別アカウントのリソースでもステートマシンから呼び出せるようになった
今までのステートマシンでのクロスアカウントアクセスのやり方(リソースベースポリシー方式)
便宜上、この記事では今までの Step Functions でのクロスアカウントアクセスの方法をリソースベースポリシー方式と呼ぶことにします。
前提として以下のような構成があるとします。
今まで、アカウント A のステートマシンからアカウント B の Lambda を呼び出すには以下の方法しかありませんでした。
- アカウント B の Lambda のリソースベースポリシーを変更し、アカウント A のリソース(ステートマシンやステートマシンに付与する IAM ロール等)からの Lambda 呼び出しを許可する
- アカウント A のステートマシンに付与する IAM ロールにアカウント B の Lambda を呼び出せる権限を付与する
- ステートマシンの定義の中でアカウント B の Lambda を呼び出すタスクを定義する
上記の IAM 権限周りも含めて絵にすると以下のような感じです。
上記の通り、呼び出し先アカウントのサービスがリソースベースポリシーをサポートしていることが前提となっています。リソースベースポリシーは全ての AWS サービスでサポートされているわけではないので、例えば別アカウントにある DynamoDB をステートマシンから直接操作することは出来ないようになっていました。
今回のアップデートにより可能となったクロスアカウントアクセスのやり方(スイッチロール方式)
便宜上、この記事ではアップデートにより追加された Step Functions のクロスアカウントアクセスの方法をスイッチロール方式と呼ぶことにします。
今回のアップデートによりステートマシン内のタスク単位で別 IAM ロールへの AssumeRole(スイッチロール)が出来るようになりました。 そのため、以下のようなやり方でも別アカウントのサービスを呼び出せるようになりました。
- アカウント B にアカウント B の Lambda を呼び出す権限を持つ IAM ロール(以後 LambdaInvokeRole)を作成する
- LambdaInvokeRole の信頼ポリシーにアカウント A のステートマシンのロール(以後 StateMRole)Arn を追加する
- StateMRole に LambdaInvokeRole に"sts:AssumeRole"出来るポリシーを追加する
- ステートマシンの定義の中でアカウント B の Lambda を呼び出すタスクを定義する。この際、新しく追加されたCredentialsというフィールドを使って、LambdaInvokeRole の Arn を指定する
やってみた
実際にステートマシンからスイッチロール方式でクロスアカウントアクセスを試してみました。 作成する構成は以下の通りです。
ステートマシンのフローはこんな感じにしました。テスト用なので意味のある処理ではないんですが、別アカウントで Lambda を動かした後、DynamoDB テーブルを作成するというフローになっています。 リソースベースポリシーを使えないサービスをステートマシンから動かしてみたくて DynamoDB を入れてみました。
ステートマシンの ASL(Amazon States Language)
ステートマシンの ASL は以下のようになります。
{ "Comment": "A Hello World example demonstrating various state types of the Amazon States Language", "StartAt": "Lambda Invoke", "States": { "Lambda Invoke": { "Type": "Task", "Resource": "arn:aws:states:::lambda:invoke", "OutputPath": "$.Payload", "Parameters": { "Payload.$": "$", "FunctionName": "arn:aws:lambda:ap-northeast-1:<アカウントBのID>:function:hello-world" }, "Credentials": { "RoleArn": "arn:aws:iam::<アカウントBのID>:role/LambdaInvokeRole" }, "Next": "CreateTable" }, "CreateTable": { "Type": "Task", "End": true, "Parameters": { "AttributeDefinitions": [ { "AttributeName": "Name", "AttributeType": "S" } ], "KeySchema": [ { "AttributeName": "Name", "KeyType": "HASH" } ], "TableName": "MyData", "BillingMode": "PAY_PER_REQUEST" }, "Resource": "arn:aws:states:::aws-sdk:dynamodb:createTable", "Credentials": { "RoleArn": "arn:aws:iam::<アカウントBのID>:role/DynamoRole" } } } }
ポイントとしては 13 行目と 38 行目の Credentials という箇所です。このフィールドが今回のアップデートで追加されていまして、タスク毎にそのタスクを実行する権限をもった IAM ロールを指定出来るようになっています。
また、各 IAM ロールの設定は以下の通りとなります。ポイントとなる箇所だけ抜粋してみました。
ステートマシンにつける IAM ロール(StateMRole) 関連
ステートマシンにつける IAM ロールに付与したポリシーは以下の通りです。別アカウントのロールに AssumeRole する権限のみがついています。
{ "Version": "2012-10-17", "Statement": [ { "Sid": "VisualEditor0", "Effect": "Allow", "Action": "sts:AssumeRole", "Resource": [ "arn:aws:iam::<アカウントBのID>:role/LambdaInvokeRole", "arn:aws:iam::<アカウントBのID>:role/DynamoRole" ] } ] }
Lambda 実行のための IAM ロール(LambdaInvokeRole) 関連
LambdaInvokeRole は ステートマシンにつけた IAM ロールから AssumeRole した上で使用します。IAM ポリシーとしてはアカウント B 上の Lambda を Invoke する権限のみがついています。
{ "Version": "2012-10-17", "Id": "default", "Statement": [ { "Sid": "myid01", "Effect": "Allow", "Action": "lambda:InvokeFunction", "Resource": "arn:aws:lambda:ap-northeast-1:<アカウントBのID>:function:hello-world" } ] }
また、信頼ポリシーは以下の通りとなっています。
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "AWS": "arn:aws:iam::<アカウントAのID>:role/service-role/StepFunctions-HelloWorld-role-5bddc095" }, "Action": "sts:AssumeRole", "Condition": { "StringEquals": { "sts:ExternalId": "arn:aws:states:ap-northeast-1:<アカウントAのID>:stateMachine:HelloWorld" } } } ] }
ここのポイントとしては、Principal としてステートマシンに付与したロールを信頼していることと、追加で、Condition により更に特定のステートマシンからしか AssumeRole 出来ないようになっていることです。
この Condition の記載はステートマシンから別アカウントのサービスを呼び出すという点においては必須ではないのですが、「混乱した代理問題」を回避するために入れることを推奨されています。
「混乱した代理問題」については弊社下記ブログをご参照ください。
DynamoDB テーブル作成のための IAM ロール(DynamoRole) 関連
DynamoRole は ステートマシンにつけた IAM ロールから AssumeRole した上で使用します。IAM ポリシーとしてはアカウント B 上で DynamoDB テーブルを作成できる権限のみがついています。
{ "Version": "2012-10-17", "Statement": [ { "Sid": "VisualEditor0", "Effect": "Allow", "Action": "dynamodb:CreateTable", "Resource": "arn:aws:dynamodb:*:<アカウントBのID>:table/MyData" } ] }
DynamoRole の信頼ポリシーは LambdaInvokeRole の信頼ポリシーとまったく同じなので割愛します
実際に動かしてみる
上記の設定で、アカウント A 上のステートマシンを動かしてみました。
ちゃんと動きましたね。別アカウント上で DynamoDB テーブルが作成されたことと Lambda が正常に終了していることも確認できました。
各タスクの結果も以下のように表示されています。別アカウント上の DynamoDB テーブルを作りましたが TableArn もちゃんと出力として返ってきていることが分かります。
どちらのクロスアカウントアクセス方法を使うのがいいのか
ステートマシンから起動する別アカウントのサービスがリソースベースポリシーをサポートしていないものである場合は、スイッチロール方式でいいと思います。
それ以外の場合はどちらが優れているというものでもないので、ケースバイケースかと思います。やりやすい方法でやるのが良いでしょう。
さいごに
AWS Step Functions のクロスアカウントアクセスに関するアップデートのご紹介でした。
Step Functions はどんどん便利になっていて頼もしいですね。今後も使用する場面は増えてきそうな予感なので、
アップデートを見逃さないようにしたいところです。
以上、とーちでした。